# -*- coding: utf-8 -*-

from time import time, strftime

import os

import wx
import wx.lib.ogl as ogl

import EntityShape as Entity

import dotsvg

import RLine


"""

todo: zooming is the next import thing!
zoom by dot? too expensive
"""

#----------------------------------------------------------------------
class SubclassDialog(wx.Dialog):
    def __init__(self):
        wx.Dialog.__init__(self, None, -1, 'Dialog Subclass',
        size=(300, 100))
        okButton = wx.Button(self, wx.ID_OK, "OK", pos=(15, 15))
        okButton.SetDefault()
        cancelButton = wx.Button(self, wx.ID_CANCEL, "Cancel",
        pos=(115, 15))



class ERDWindow(ogl.ShapeCanvas):
    def __init__(self, parent, log, frame):
        ogl.ShapeCanvas.__init__(self, parent)

        maxWidth  = 2000
        maxHeight = 2000
        
        self.cursor_sizing = wx.StockCursor(wx.CURSOR_SIZING)   
        
        self.SetScrollbars(20, 20, maxWidth/20, maxHeight/20)

        self.log = log
        self.frame = frame
        self.SetBackgroundColour(wx.WHITE) #"LIGHT BLUE") #
        self.diagram = ogl.Diagram()
        self.SetDiagram(self.diagram)
        self.diagram.SetCanvas(self)
        self.shapes = []
        self.save_gdi = []
        self.Bind(wx.EVT_MOTION, self.OnMouseMove)



        #rRectBrush = wx.Brush("MEDIUM TURQUOISE", wx.SOLID)
        self.dsBrush = wx.Brush("WHEAT", wx.SOLID)
        self.dsBrush = wx.Brush("WHITE", wx.SOLID)
        
        dotstr = """ 
         digraph G {
          rankdir=TB;
          nodesep =1;
          node [shape=record];
          a [ label ="{  Graphs can\lbe fun\l|  mid|  right}"];
          b [ label ="{  |   b |   }" ];
          c [ label ="{    | c |    }" ];
          x [ label ="{    | x |   }" ];
          y [ label ="{   | y |    }" ];
          z [ id="z", label ="{  a | z | p2   }" ];
          a -> b ;
          a  -> d;
          a  -> y ;
          c  -> d;
          b  -> x ;
          c  -> y ;
          b  -> z;
        }
        """

        ### care the \n in dot str, should use \\n to make the dot file correct
        dotstr ="""

digraph Alf {
size = "6,9";
node [ shape = record ];
Decl [ label = "\\n\\nDecl|{name|access|decl_flags|extern_c_linkage}"];
Nontype_decl [ label = "Nontype_decl|{type}"];
Defined_decl [ label = "Defined_decl|{linkage}"];
Data_decl [ label = "Data_decl|{storage_class}"];
Function_decl [ label = "Function_decl|{formals|defaults}"];
Data [ label = "Data|{initializer}"];
Function [ label = "Function|{body}"];
Constructor [ label = "Constructor|{member_initializers}"];
Aggregate ->  Type_decl ;
Class -> Aggregate;
Union -> Aggregate;
Data -> Data_decl;
Data -> Defn;
Data_decl -> Defined_decl;
Data_member ->  Nontype_decl ;
Defined_decl -> Nontype_decl;
Defn -> Defined_decl;
Enum ->  Type_decl ;
Enumerator ->  Nontype_decl ;
Function -> Defn;
Function -> Function_decl;
Constructor -> Function;
Destructor -> Function;
Function_decl -> Defined_decl;
Nontype_decl ->  Decl ;
Template_type_arg ->  Type_decl ;
Type_decl ->  Decl ;
Typedef ->  Type_decl ;
}


        """
        
        dotstr = """
   digraph G {
    rankdir=TB;
    nodesep =0.5;
    node [shape=record];
            Decl [label="Decl" pos="648.5,524.0" ];
            name;
            lll;
            test;
Nontype_decl [label="Nontype_decl" pos="506.0,422.0" ];
Defined_decl [label="Defined_decl" pos="313.5,350.0" ];
Data_decl [label="Data_decl" pos="186.5,272.0" ];
Function_decl [label="Function_decl" pos="436.0,272.0" ];
Data [label="Data" pos="246.0,194.0" ];
Defn [label="Defn" pos="313.0,272.0" ];
Function [label="Function" pos="405.5,194.0" ];
Constructor [label="Constructor" pos="325.5,122.0" ];
Aggregate [label="Aggregate" pos="656.5,350.0" ];
Type_decl [label="Type_decl" pos="738.0,422.0" ];
Class [label="Class" pos="620.0,272.0" ];
Union [label="Union" pos="692.0,272.0" ];
Data_member [label="Data_member" pos="453.0,350.0" ];
Enum [label="Enum" pos="738.0,350.0" ];
Enumerator [label="Enumerator" pos="560.0,350.0" ];
Destructor [label="Destructor" pos="485.0,122.0" ];
Template_type_arg [label="Template_type_arg" pos="844.0,350.0" ];
Typedef [label="Typedef" pos="954.0,350.0" ];
Nontype_decl->Decl;
Defined_decl->Nontype_decl;
Data_decl->Defined_decl;
Function_decl->Defined_decl;
Data->Data_decl;
Data->Defn;
Function->Function_decl;
Function->Defn;
Constructor->Function;
Aggregate->Type_decl;
Type_decl->Decl;
Class->Aggregate;
Union->Aggregate;
Defn->Defined_decl;
Data_member->Nontype_decl;
Enum->Type_decl;
Enumerator->Nontype_decl;
Destructor->Function;
Template_type_arg->Type_decl;
Typedef->Type_decl;
 }     
        
        """
        
        #create a file
        #todo: create a memory file
        # Popen use stdin
        
        f = open("er.dot","w")
        f.write(dotstr)
        f.close()
        
        # dot cmd 
        cmd = "dot.exe -Tsvg er.dot"
        mode = "b"
        bufsize = -1
        (child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)        
        xml =""
        for line in child_stdout:
            xml = xml + line
        #print xml
        try:        
            x_offset = 100
            y_offset = 100
            svg = dotsvg.DotSVG(xml, x_offset, y_offset)
            
        except Exception, e:
            print e
        
        for nd in svg.graph.nodes:
            #print nd.name        
            nd.og = self.MyAddShape(
                Entity.EntityShape(nd.name,nd.width, nd.height, self), 
                nd.x, nd.y, wx.BLACK_PEN, self.dsBrush, ''
                )
        
        """
        self.MyAddShape(
            Entity.EntityShape('name1',140, 150, self), 
            420, 165, wx.BLACK_PEN, self.dsBrush, ''
            )            

        self.MyAddShape(
            Entity.EntityShape('name2',140, 150, self), 
            820, 165, wx.BLACK_PEN, self.dsBrush, ''
            )   
        """
        dc = wx.ClientDC(self)
        self.PrepareDC(dc)
        for ln in svg.graph.edges:
            fromShape =  svg.graph.nodes_dict[ln.nodefrom].og
            toShape =  svg.graph.nodes_dict[ln.nodeto].og
            line = RLine.RLine(self, fromShape, toShape, ln.name)
            
            self.diagram.AddShape(line)
            line.Show(True)
        """
        for x in range(len(self.shapes)):
            fromShape = self.shapes[x]
            if x+1 == len(self.shapes):
                toShape = self.shapes[0]
            else:
                toShape = self.shapes[x+1]
            
            line = RLine.RLine(self, fromShape, toShape)
            
            self.diagram.AddShape(line)
            line.Show(True)
        """
        
        """
        for x in range(len(self.shapes)):
            if isinstance(self.shapes[x],DividedShape):
                print "%s" %(self.shapes[x].name)
        """
        
        lt = self.diagram.GetShapeList()
        for x in range( len(lt)):
            if isinstance(lt[x],RLine.RLine):
                #print "wx.lib.ogl._lines.LineShape"
                l = lt[x]
                #print "from " + l.GetFrom().name
                #print "to " + l.GetTo().name
    
    def Shapes2Dot(self):
        ol =self.diagram.GetShapeList()
        dotstr = """
    digraph G {
    rankdir=TB;
    nodesep =1;
    node [shape=record];
            """
        for item in ol:
            #print item #features.UI.perspective.erview.EntityShape.EntityShape
            if isinstance(item, Entity.EntityShape):
                (x, y) = item.GetPos()
                dotstr = dotstr + "%s [label=\"%s\" pos=\"%s,%s\" ];\n" %(item.name, item.name, x,y)
                #pos="153,144"
            elif isinstance(item, RLine.RLine):
                dotstr = dotstr + "%s;\n" %(item.name)
            else:
                pass
                    
        dotstr = dotstr + " } \n"
        print dotstr
        
    
    def Shape2Json(self):        
        ol =self.diagram.GetShapeList()
        dotstr = """
    digraph G {
    rankdir=TB;
    nodesep =1;
    node [shape=record];
            """
        for item in ol:
            #print item #features.UI.perspective.erview.EntityShape.EntityShape
            if isinstance(item, Entity.EntityShape):
                (x, y) = item.GetPos()
                dotstr = dotstr + "%s [label=\"%s\" pos=\"%s,%s\" ];\n" %(item.name, item.name, x,y)
                #pos="153,144"
            elif isinstance(item, RLine.RLine):
                dotstr = dotstr + "%s;\n" %(item.name)
            else:
                pass
                    
        dotstr = dotstr + " } \n"
        print dotstr

    def MyDeleteShape(self, shape):
        lt = self.diagram.GetShapeList()
        lt.remove(shape)
        shape.Delete()
        """
        for x in range( len(lt)):
            if isinstance(lt[x],RLine.RLine):
                print lt[x]
                if lt[x] == shape:
                    lt.remove(shape)
        """
                

    def MyAddShape(self, shape, x, y, pen, brush, text):
        # Composites have to be moved for all children to get in place
        if isinstance(shape, ogl.CompositeShape):
            dc = wx.ClientDC(self)
            self.PrepareDC(dc)
            shape.Move(dc, x, y)
        else:
            shape.SetDraggable(True, True)
        shape.SetCanvas(self)
        shape.SetX(x)
        shape.SetY(y)
        if pen:    shape.SetPen(pen)
        if brush:  shape.SetBrush(brush)
        if text:
            for line in text.split('\n'):
                shape.AddText(line)
        #shape.SetShadowMode(ogl.SHADOW_RIGHT)
        self.diagram.AddShape(shape)
        shape.Show(True)
        self.shapes.append(shape)
        return shape


    def OnMouseMove(self, event):
        (x, y) =  event.GetPosition()
        (s,a) = self.FindShape(x, y)
        #print s
        if s != None and isinstance(s, Entity.EntityShape):
            #print "over %s,%s"  %(x, y)
                 
            self.frame.SetCursor(self.cursor_sizing)
        else:
            pass
        self.frame.SetStatusText("Pos: (%d, %d)" %(x,y))
        event.Skip()

        
    def OnLeftClick(self, x, y, keys):
        """
        self.MyAddShape(Entity.EntityShape('name3',140, 150, self), 
            x, y, wx.BLACK_PEN, self.dsBrush, ''
            ) 
        """
        #dialog = SubclassDialog()
        #result = dialog.ShowModal()
        #self.Refresh()
        pass
        #print ("OnLeftClick: %s, %s, %s\n" % (x, y, keys))
        
    def OnRightClick(self, x, y, keys):        
        self.Shapes2Dot()
        pass
        #print ("OnRightClick: %s, %s, %s\n" % (x, y, keys))        

    """
    def OnDragLeft(self, draw, x, y, keys):
        self.log.write("OnDragLeft: %s, %s, %s\n" % (x, y, keys))
    """
    
    def OnBeginDragLeft(self, x, y, keys):
        pass
        #print ("OnBeginDragLeft: %s, %s, %s\n" % (x, y, keys))

    def OnEndDragLeft(self, x, y, keys):
        pass
        #print ("OnEndDragLeft: %s, %s, %s\n" % (x, y, keys))

def test():
    print "run"


if __name__ == "__main__":
    test()
